﻿using HandyControl.Controls;
using HandyControl.Data;
using HandyControl.Interactivity;
using HandyControl.Tools;
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;

namespace LpbPrj.Client.Controls;

/// <summary>
///     颜色选择器
/// </summary>
[TemplatePart(Name = ElementRoot, Type = typeof(Grid))]
[TemplatePart(Name = ElementBorder, Type = typeof(Border))]
[TemplatePart(Name = ElementButton, Type = typeof(Button))]
[TemplatePart(Name = ElementPopup, Type = typeof(Popup))]
public class ColorPickerEx : Control
{
    #region Constants

    private const string ElementRoot = "PART_Root";

    private const string ElementBorder = "PART_Border";

    private const string ElementButton = "PART_Button";

    private const string ElementPopup = "PART_Popup";

    #endregion Constants

    #region Data

    private ButtonBase _dropDownButton;

    private Popup _popup;

    private bool _disablePopupReopen;

    private Border _brushBorder;

    #endregion Data

    #region Public Events

    public static readonly RoutedEvent SelectedBrushChangedEvent = EventManager.RegisterRoutedEvent("SelectedBrushChanged", RoutingStrategy.Direct, typeof(EventHandler<FunctionEventArgs<Brush>>), typeof(ColorPickerEx));

    public event EventHandler<FunctionEventArgs<Brush>> SelectedBrushChanged
    {
        add => AddHandler(SelectedBrushChangedEvent, value);
        remove => RemoveHandler(SelectedBrushChangedEvent, value);
    }

    #endregion Public Events

    static ColorPickerEx()
    {
        KeyboardNavigation.TabNavigationProperty.OverrideMetadata(typeof(ColorPickerEx), new FrameworkPropertyMetadata(KeyboardNavigationMode.Once));
        KeyboardNavigation.IsTabStopProperty.OverrideMetadata(typeof(ColorPickerEx), new FrameworkPropertyMetadata(false));
    }

    public ColorPickerEx()
    {
        CommandBindings.Add(new CommandBinding(ControlCommands.Clear, (s, e) =>
        {
            SetCurrentValue(SelectedBrushProperty, ResourceHelper.GetResource<System.Windows.Media.SolidColorBrush>("DefaultBackgroundBrush"));
            _brushBorder.Background = ResourceHelper.GetResource<System.Windows.Media.SolidColorBrush>("DefaultBackgroundBrush");
        }));
    }


    public bool IsDropDownOpen
    {
        get => (bool)GetValue(IsDropDownOpenProperty);
        set => SetValue(IsDropDownOpenProperty, value);
    }
    public static readonly DependencyProperty IsDropDownOpenProperty = DependencyProperty.Register(
            nameof(IsDropDownOpen), typeof(bool), typeof(ColorPickerEx), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnIsDropDownOpenChanged, OnCoerceIsDropDownOpen));
    private static object OnCoerceIsDropDownOpen(DependencyObject d, object baseValue)
    {
        return d is ColorPickerEx { IsEnabled: false }
            ? false
            : baseValue;
    }
    private static void OnIsDropDownOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var dp = d as ColorPickerEx;

        var newValue = (bool)e.NewValue;
        if (dp?._popup != null && dp._popup.IsOpen != newValue)
        {
            dp._popup.IsOpen = newValue;
            //if (newValue && dp.BrushPicker != null)
            //{
            //    dp.BrushPicker.SelectedBrush = dp.SelectedBrush;
            //}
        }
    }


    public SolidColorBrush SelectedBrush
    {
        get => (SolidColorBrush)GetValue(SelectedBrushProperty);
        set => SetValue(SelectedBrushProperty, value);
    }
    public static readonly DependencyProperty SelectedBrushProperty = DependencyProperty.Register(
            nameof(SelectedBrush), typeof(SolidColorBrush), typeof(ColorPickerEx), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSelectedBrushChanged, CoerceSelectedBrush));
    private static void OnSelectedBrushChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is not ColorPickerEx dp) return;
        if (dp._brushBorder != null)
        {
            dp._brushBorder.Background = dp.SelectedBrush;
        }
        dp.RaiseEvent(new FunctionEventArgs<SolidColorBrush>(SelectedBrushChangedEvent, dp)
        {
            Info = dp.SelectedBrush
        });
    }
    private static object CoerceSelectedBrush(DependencyObject d, object value)
    {
        var dp = (ColorPickerEx)d;
        if (dp.BrushPicker is null && value is null)
        {
            return Brushes.White;
        }
        if (dp.BrushPicker is null && value is SolidColorBrush brush)
        {
            return brush;
        }
        return dp.BrushPicker.SelectedBrush;
    }


    public static readonly DependencyProperty BrushPickerProperty = DependencyProperty.Register(
        nameof(BrushPicker), typeof(ColorPicker), typeof(ColorPickerEx), new FrameworkPropertyMetadata(default(ColorPicker), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnBrushPickerChanged));
    private static void OnBrushPickerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var ctl = (ColorPickerEx)d;

        if (e.OldValue is ColorPicker oldClock)
        {
            oldClock.SelectedColorChanged -= ctl.ColorPicker_SelectedBrushChanged;
            oldClock.Confirmed -= ctl.ColorPicker_Confirmed;
            ctl._popup.Child = null;
        }

        if (e.NewValue is ColorPicker newClock)
        {
            //newClock.ShowConfirmButton = true;
            newClock.SelectedColorChanged += ctl.ColorPicker_SelectedBrushChanged;
            newClock.Confirmed += ctl.ColorPicker_Confirmed;
            ctl._popup.Child = newClock;
        }
    }
    public ColorPicker BrushPicker
    {
        get => (ColorPicker)GetValue(BrushPickerProperty);
        set => SetValue(BrushPickerProperty, value);
    }


    public override void OnApplyTemplate()
    {
        if (DesignerProperties.GetIsInDesignMode(this)) return;
        if (_popup != null)
        {
            _popup.PreviewMouseLeftButtonDown -= PopupPreviewMouseLeftButtonDown;
            _popup.Opened -= PopupOpened;
            _popup.Closed -= PopupClosed;
            _popup.Child = null;
        }
        if (_dropDownButton != null)
        {
            _dropDownButton.Click -= DropDownButton_Click;
            _dropDownButton.MouseLeave -= DropDownButton_MouseLeave;
        }

        base.OnApplyTemplate();

        _popup = GetTemplateChild(ElementPopup) as Popup;
        _dropDownButton = GetTemplateChild(ElementButton) as Button;
        _brushBorder = GetTemplateChild(ElementBorder) as Border;
        if (_dropDownButton == null || _popup == null || _brushBorder == null) throw new Exception();

        if (BrushPicker is null)
        {
            SetCurrentValue(BrushPickerProperty, new ColorPicker());
        }

        _popup.PreviewMouseLeftButtonDown += PopupPreviewMouseLeftButtonDown;
        _popup.Opened += PopupOpened;
        _popup.Closed += PopupClosed;
        _popup.Child = BrushPicker;

        _dropDownButton.Click += DropDownButton_Click;
        _dropDownButton.MouseLeave += DropDownButton_MouseLeave;

        _brushBorder?.SetBinding(BackgroundProperty, new Binding(SelectedBrushProperty.Name) { Source = this });
        //SetCurrentValue(SelectedBrushProperty, ResourceHelper.GetResource<System.Windows.Media.SolidColorBrush>("RegionBrush"));
        BrushPicker.SelectedBrush = SelectedBrush;
    }

    private void DropDownButton_MouseLeave(object sender, MouseEventArgs e)
    {
        _disablePopupReopen = false;
    }

    private void PopupPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        if (sender is Popup { StaysOpen: false })
        {
            if (_dropDownButton?.InputHitTest(e.GetPosition(_dropDownButton)) != null)
            {
                _disablePopupReopen = true;
            }
        }
    }

    private void ColorPicker_SelectedBrushChanged(object sender, FunctionEventArgs<Color> e)
    {
        //SelectedBrush = new SolidColorBrush(e.Info);
    }

    private void ColorPicker_Confirmed(object sender, FunctionEventArgs<Color> e)
    {
        SelectedBrush = new SolidColorBrush(e.Info);
        TogglePopup();
    }

    private void PopupOpened(object sender, EventArgs e)
    {
        if (!IsDropDownOpen)
        {
            SetCurrentValue(IsDropDownOpenProperty, true);
        }
        //BrushPicker?.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
    }

    private void PopupClosed(object sender, EventArgs e)
    {
        if (IsDropDownOpen)
        {
            SetCurrentValue(IsDropDownOpenProperty, false);
        }

        //if (BrushPicker.IsKeyboardFocusWithin)
        //{
        //    MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
        //}
    }

    private void DropDownButton_Click(object sender, RoutedEventArgs e) => TogglePopup();

    private void TogglePopup()
    {
        if (IsDropDownOpen)
        {
            SetCurrentValue(IsDropDownOpenProperty, false);
        }
        else
        {
            if (_disablePopupReopen)
            {
                _disablePopupReopen = false;
            }
            else
            {
                SetCurrentValue(SelectedBrushProperty, _brushBorder.Background);
                SetCurrentValue(IsDropDownOpenProperty, true);
            }
        }
    }

}
